#include <stdio.h>

//ntohl,ntohs,htonl,htons,函数本身不做大小端判断，即重复使用同一函数两次，相当于没有转
//INET_ADDRSTRLEN，INET6_ADDRSTRLEN
#include <netinet/in.h>

#include <arpa/inet.h> // 字符串类型ip转整数类型ip
#include <bits/socket.h>//协议族，AF_INET

#include <assert.h>

#include <sys/types.h>
#include <sys/socket.h> // socket api

#include <unistd.h> //close

#include <strings.h> //bzero

#include <string.h> //strlen strcmp

#include <stdlib.h> // atoi



const char strIP4[] = "192.168.242.134";




//telnet 192.168.242.134 8088
//netstat -nt | grep 8088




union endint
{
    int littleEndian;
    unsigned char b;
};


void testEndian()
{
    union endint test;
    test.littleEndian = 0x01020304;
    printf("num : %08x\n", test.littleEndian);

//    test.littleEndian = htonl(test.littleEndian);//转为大端

    if (1 == test.b)
    {
        printf("this is big endian\n");
    }
    else if (4 == test.b)
    {
        printf("this is little endian\n");
    }
    else
    {
        printf("unkonw endlian\n");
    }
}


void runCli(const char* strip, int port)
{
    //创建socket
    int clientSocketfd = socket(PF_INET, SOCK_STREAM, 0);
    assert(clientSocketfd > -1);

    //发起连接
    struct sockaddr_in serverAddr;
    bzero(&serverAddr, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    inet_pton(AF_INET, strip, &serverAddr.sin_addr);
    serverAddr.sin_port = htons(port);
    int ret = connect(clientSocketfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));//阻塞函数
    assert(0 == ret);

    const char* sendbuf = "i am client\n";
    char recvbuf[1024];

    send(clientSocketfd, sendbuf, strlen(sendbuf), 0);
    recv(clientSocketfd, recvbuf, 1024, 0);
    printf("recv msg from ser:%s\n", recvbuf);

    while (1)
    {
        sleep(1);
    }

    //关闭
    shutdown(clientSocketfd, SHUT_RDWR);
}



int main(int argc, char* argv[])//argv第一个参数是文件名，后面是自己加的
{
//    testEndian();


    if (argc < 4)
    {
        printf("\nparm count little\n");
    }

    const char* role = argv[1];//cli or ser
    const char* strip = argv[2];
    int port = atoi(argv[3]);

    if (0 == strcmp(role, "cli"))
    {
        runCli(strip, port);
        printf("\nclient close\n");
        return 0;
    }
    else if ((0 == strcmp(role, "ser")))
    {
        printf("server is running\n");
    }


    //字符串ip转换
    uint32_t ipvt4;
    int ret = inet_pton(AF_INET, strIP4, &ipvt4);//字符串ip转换为大端整数表示
    assert(1 == ret);
    ipvt4 = ntohl(ipvt4);
    printf("the ip num is %08x\n", ipvt4);

    char stripBuf[INET_ADDRSTRLEN];
    const char* addr = inet_ntop(AF_INET, &ipvt4, stripBuf, INET_ADDRSTRLEN);//大端整数转为字符串
    assert(NULL != addr);

    printf("str ip : %s\n", stripBuf);


    //use socket
    {

    //创建socket
    int serverSocketfd = socket(PF_INET, SOCK_STREAM, 0);
    assert(serverSocketfd > -1);

    //命名，客户端通常不需要命名，服务端需要
    struct sockaddr_in addr;
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    inet_pton(AF_INET, strip, &addr.sin_addr);
    addr.sin_port = htons(port);

    int ret = bind(serverSocketfd, (struct sockaddr*)&addr, sizeof(addr));
    assert(-1 != ret);//EADDRINUSE

    //监听
    ret = listen(serverSocketfd, 5);
    assert(0 == ret);

    struct sockaddr_in clientAddr;
    socklen_t clientAddrLen = sizeof(clientAddr);
    int clientSocketfd = accept(serverSocketfd, (struct sockaddr*)&clientAddr, &clientAddrLen);//阻塞函数
    assert(-1 != clientSocketfd);

    if (clientSocketfd > -1)
    {
        char strClientip[INET_ADDRSTRLEN];


        printf("conn succ ip:%s and port:%d\n"
               , inet_ntop(AF_INET, &clientAddr.sin_addr, strClientip, INET_ADDRSTRLEN)
               , ntohs(clientAddr.sin_port));
    }


    const char* sendbuf = "3。141592\n";
    char recvbuf[1024];

    recv(clientSocketfd, recvbuf, 1024, 0);
    printf("recv msg from cli:%s\n", recvbuf);

    send(clientSocketfd, sendbuf, strlen(sendbuf), 0);


    while (1)
    {
        sleep(1);
    }


    //关闭
    close(serverSocketfd);
    shutdown(clientSocketfd, SHUT_RDWR);
    }



    printf("server close\n");
    return 0;
}
